// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>

// // 交换两个字符
// void swap(char *x, char *y) {
//     char temp = *x;
//     *x = *y;
//     *y = temp;
// }

// // 检查字符是否已经使用过
// int shouldSwap(char *str, int start, int curr) {
//     for (int i = start; i < curr; i++) {
//         if (str[i] == str[curr]) {
//             return 0;
//         }
//     }
//     return 1;
// }

// // 递归生成排列
// void permute(char *str, int start, int end) {
//     if (start == end) {
//         printf("%s\n", str);
//     } else {
//         for (int i = start; i <= end; i++) {
//             // 检查是否需要交换
//             if (shouldSwap(str, start, i)) {
//                 swap(&str[start], &str[i]);
//                 permute(str, start + 1, end);
//                 swap(&str[start], &str[i]); // 回溯
//             }
//         }
//     }
// }

// int main() {
//     char str[10];
//     scanf("%s",str);
//     int n = strlen(str);
//     permute(str, 0, n - 1);
//     return 0;
// }

// class Person
// {
//     public:
//         const char* Getname()
//         {
//             return _name;
//         }
//     protected:
//       char* _name="123";
// };

// class student:public Person
// {
//     public:
//         const char* Getname()
//         {
//             _name="abc";
//             return _name;
//         }
//     private:
//         char* _name="213123";
// };

// int main()
// {
//     student stu;
//     stu.Getname();

//     return 0;
// }
//  Student的 _num和Person的_num构成隐藏关系，可以看出这样代码虽然能跑，但是非常容易混淆
// #include <iostream>
// using namespace std;

// class Person
// {
// protected:
// 	string _name = "小李子";
// 	int _num = 111;  // 身份证号
// };
// class Student :public Person
// {
// public:
// 	void Print()
// 	{
// 		cout << "姓名:" << _name << endl;
// 		cout << "身份证号:" << Person::_num <<                                                                                                endl;
// 		cout << "学号:" << _num << endl;
// 	}

// protected:
// 	int _num = 999;  // 学号
// };
// void Test()
// {
// 	Student s;
// 	s.Print();

// }
// int main()
// {
//     Test();
// }
// void TestConstRef()
// {
// 	//1.
// 	// int& c = 2 + 3;  // 会报错
// 	// 因为 2+3的结果是存储在一个const 修饰的 临时空间的
// 	//所以需要用const 来修饰引用
// 	const int& rc = 2 + 3;

// 	//2.
// 	const int a = 10;
// 	// int&  ra= a; // 该语句编译时会出错，a为常量
// 	const int& ra = a;

// 	//3.
// 	// int& b = 10;    该语句编译时会出错，同第一个一样，10存储在以const修饰的空间
// 	const int& b = 10;

// 	//4.
// 	double d = 12.34;
// 	//int& rd = d; //语句编译时出错，类型不同
// 	//int & rrrd = rrd;    // 涉及到类型转换，底层转换是将 数值存储const 修饰的临时空间中，然后把所需要的数值截取出来，所以也是const 修饰
// 	const int& rd = d;
// 	const double& rrd = rd;
// }
// #include <cstdio>
// int main()
// {
// 	int a = 10;
// 	// int& ra;   该条语句编译时会出错
// 	int& ra = a;
// 	int& rra = ra;
// 	printf("%p %p %p\n", &a, &ra, &rra);
//     // 0x7ffdd64b6e28 0x7ffdd64b6e28 0x7ffdd64b6e28

//     int& b=a;
//     int c=20;
//      b=c;    //这里并非让b引用c，因为C++引用不能改变指向，
//             // 这里是一个赋值到a的操作
//     printf("%d\n",a);   /// 20

// 	return 0;
// }
#include<iostream>
using namespace std;

class Person
{
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student :public Person
{
public:
	virtual void BuyTicket() { cout << "买票-半价" << endl; }

	/*	在重写基类虚函数时，派生类的虚函数在不加virtual关键字时，虽然也可以构成重写（因为继承后基类的
虚函数被继承下来了在派生类依旧保持虚函数属性），但是这种写法不是很规范，不建议这样使用。
	void BuyTicket() { cout << "买票-半价" << endl; }
*/

};
void Test1(Person& p)
{
	p.BuyTicket();
}
void Test2(Person* p)
{
	p->BuyTicket();
}

int main()
{
	Person p;
	Student s;
	
	Test1(p); // 全价
	Test1(s);  // 半价

	Person& rp = p;
	Student& rs = s;

	Test1(rp); // 全价
	Test1(rs);  // 半价

	rp = s;
	Test1(rp);   // 全价
	rs =(Student&) p;
	Test1(rs);   // 半价

	// Person* pp=&p;  
	// Student* ps=&s;   

	// Test2(pp);  // 全价
	// Test2(ps);  // 半价

	// p = s;
	// Test1(p);  // 输出为全价，派生类切片赋值给基类，但本质上还是基类

	// pp = &s;
	// Test2(pp);  //半价   pp虽然是基类指针，但他指向派生类，所以输出是半价

	//ps = &p;
	//ps =(Student*) & p;
	
	// 子类对象可以直接切片赋值给父类对象  
	// 子类指针不能直接指向父类对象地址,但是可以强行转换成子类指针赋值，虽然这样可以，但是会存在越界问题
	// 子类引用同样不能直接赋值父类对象，但是可以通过强转完成赋值
	// 父类对象不能直接赋值给子类对象
	// 父类指针可以指向子类对象地址，实现调用子类的多态功能
	// 父类引用可以直接引用子类对象，但是调用的还是父类的多态


	return 0;
}